<template>
  <div class="app-container">
    <!-- 筛选栏 -->
    <el-form :inline="true" size="small" class="filter-bar">
      <el-form-item label="时间范围">
        <el-date-picker v-model="filters.range"
                         type="datetimerange"
                         range-separator="至"
                         start-placeholder="开始时间"
                         end-placeholder="结束时间"
                         value-format="yyyy-MM-dd HH:mm:ss"
                         :unlink-panels="true" />
      </el-form-item>
      <el-form-item label="趋势粒度">
        <el-radio-group v-model="filters.trendGranularity">
          <el-radio-button label="day">日</el-radio-button>
          <el-radio-button label="week">周</el-radio-button>
          <el-radio-button label="month">月</el-radio-button>
        </el-radio-group>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" @click="loadAll">查询</el-button>
      </el-form-item>
      <el-form-item>
        <el-button icon="el-icon-refresh" @click="resetFilters">重置</el-button>
      </el-form-item>
    </el-form>

    <!-- 工具栏 -->
    <el-row :gutter="10" class="mb8">
      <el-col :span="12">
        <el-button icon="el-icon-refresh" size="mini" @click="loadAll">刷新</el-button>
        <el-button type="warning" icon="el-icon-download" size="mini" @click="exportRealtime">导出实时CSV</el-button>
        <el-button type="warning" icon="el-icon-download" size="mini" @click="exportExceptions">导出异常CSV</el-button>
        <el-button type="success" icon="el-icon-picture-outline" size="mini" @click="exportCharts">导出图表PNG</el-button>
      </el-col>
    </el-row>

    <!-- 概览卡片 -->
    <el-row :gutter="12" class="summary-row">
      <el-col :span="6">
        <el-card shadow="never"><div class="metric">总看板数</div><div class="value">{{ summary.totalKanban || 0 }}</div></el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="never"><div class="metric">完成数量</div><div class="value success">{{ summary.completedKanban || 0 }}</div></el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="never"><div class="metric">异常数量</div><div class="value warning">{{ summary.exceptionKanban || 0 }}</div></el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="never"><div class="metric">取消数量</div><div class="value info">{{ summary.cancelKanban || 0 }}</div></el-card>
      </el-col>
    </el-row>
    <el-row :gutter="12" class="summary-row">
      <el-col :span="6">
        <el-card shadow="never"><div class="metric">准时率</div><div class="value">{{ (summary.onTimeRate || 0) }}%</div></el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="never"><div class="metric">平均完成时长</div><div class="value">{{ (summary.avgCompletionHours || 0) }}h</div></el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="never"><div class="metric">超时数量</div><div class="value warning">{{ summary.overtimeCount || 0 }}</div></el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="never"><div class="metric">OTIF</div><div class="value">{{ (summary.otifRate || 0) }}%</div></el-card>
      </el-col>
    </el-row>

    <!-- 趋势与分布 -->
    <el-row :gutter="12">
      <el-col :span="16">
        <el-card shadow="never" class="chart-card"><div ref="trendRef" class="chart"></div></el-card>
      </el-col>
      <el-col :span="8">
        <el-card shadow="never" class="chart-card"><div ref="distRef" class="chart"></div></el-card>
      </el-col>
    </el-row>

    <!-- 实时表 + 异常统计 -->
    <el-row :gutter="12" style="margin-top:12px">
      <el-col :span="16">
        <el-card shadow="never">
          <!-- 子筛选栏（对当前页实时数据进行本地过滤） -->
          <div class="sub-filter">
            <el-input v-model="tableFilters.search" size="mini" clearable placeholder="搜索看板编码/仓库" style="width: 220px; margin-right:8px" />
            <el-select v-model="tableFilters.status" size="mini" clearable placeholder="业务状态" style="width: 160px; margin-right:8px">
              <el-option v-for="opt in statusOptions" :key="opt" :label="opt" :value="opt" />
            </el-select>
            <el-button icon="el-icon-close" size="mini" @click="clearTableFilters">清空筛选</el-button>
          </div>
          <el-table :data="realtimeFiltered" height="380" border stripe @row-dblclick="handleRowDblClick">
            <el-table-column prop="kanbanCode" label="看板编码" width="160" />
            <el-table-column label="业务状态" width="110">
              <template slot-scope="scope">
                <el-tag :type="statusTagType(scope.row.businessStatus)" size="small">{{ scope.row.businessStatus }}</el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="receiverWarehouse" label="收货库房" width="180" />
            <el-table-column prop="senderWarehouse" label="发货库房" width="180" />
            <el-table-column prop="requiredDeliveryTime" label="要求到货" width="168" sortable />
            <el-table-column prop="plannedDeliveryTime" label="计划发货" width="168" sortable />
            <el-table-column prop="createTime" label="创建时间" width="168" sortable />
          </el-table>
          <div style="margin-top:8px; text-align:right">
            <el-pagination
              :current-page="pagination.pageNum"
              :page-size="pagination.pageSize"
              :total="pagination.total"
              layout="total, sizes, prev, pager, next, jumper"
              :page-sizes="[10, 20, 50, 100]"
              @current-change="handlePageChange"
              @size-change="handleSizeChange"
            />
          </div>
        </el-card>
      </el-col>
      <el-col :span="8">
        <el-card shadow="never" class="chart-card"><div ref="exceptionRef" class="chart"></div></el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import * as api from '@/api/kanban/dashboard'
import * as echarts from 'echarts'
import { saveAs } from 'file-saver'

export default {
  name: 'KanbanDashboard',
  data() {
    return {
      loading: false,
      summary: {},
      trend: [],
      distribution: [],
      realtimeList: [],
      exceptions: [],
      pagination: { pageNum: 1, pageSize: 10, total: 0 },
      filters: {
        range: [],
        trendGranularity: 'day'
      },
      // 子筛选（本地过滤当前页实时数据）
      tableFilters: {
        search: '',
        status: ''
      },
      statusOptions: ['草稿', '已发货', '已收货', '已作废']
    }
  },
  mounted() {
    this.loadAll()
    this.$nextTick(() => {
      this.renderTrend()
      this.renderDist()
      this.renderException()
    })
  },
  computed: {
    realtimeFiltered() {
      const s = (this.tableFilters.search || '').trim()
      const st = (this.tableFilters.status || '').trim()
      return (this.realtimeList || []).filter(it => {
        const matchSearch = !s ||
          String(it.kanbanCode || '').includes(s) ||
          String(it.senderWarehouse || '').includes(s) ||
          String(it.receiverWarehouse || '').includes(s)
        const matchStatus = !st || String(it.businessStatus || '') === st
        return matchSearch && matchStatus
      })
    }
  },
  methods: {
    params() {
      const p = { trendGranularity: this.filters.trendGranularity }
      if (this.filters.range && this.filters.range.length === 2) {
        p.startTime = this.filters.range[0]
        p.endTime = this.filters.range[1]
      }
      return p
    },
    resetFilters() {
      this.filters.range = []
      this.filters.trendGranularity = 'day'
      this.loadAll()
    },
    async loadAll() {
      this.loading = true
      try {
        const [summaryRes, trendRes, distRes, realtimeRes, exceptionRes] = await Promise.all([
          api.getReceiverSummary(this.params()),
          api.getReceiverTrend(this.params()),
          api.getReceiverDistribution(this.params()),
          api.getReceiverRealtime({ ...this.params(), pageNum: this.pagination.pageNum, pageSize: this.pagination.pageSize }),
          api.getReceiverExceptions(this.params())
        ])
        this.summary = summaryRes.data || {}
        this.trend = trendRes.data || []
        this.distribution = distRes.data || []
        // TableDataInfo format: { rows, total }
        this.realtimeList = (realtimeRes.rows || realtimeRes.data || [])
        this.pagination.total = realtimeRes.total || 0
        this.exceptions = exceptionRes.data || []
        this.renderTrend()
        this.renderDist()
        this.renderException()
      } finally {
        this.loading = false
      }
    },
    handlePageChange(page) {
      this.pagination.pageNum = page
      this.loadAll()
    },
    handleSizeChange(size) {
      this.pagination.pageSize = size
      this.pagination.pageNum = 1
      this.loadAll()
    },
    clearTableFilters() {
      this.tableFilters.search = ''
      this.tableFilters.status = ''
    },
    statusTagType(text) {
      switch (text) {
        case '草稿': return 'info'
        case '已发货': return 'warning'
        case '已收货': return 'success'
        case '已作废': return 'danger'
        default: return 'default'
      }
    },
    // ===== 图表渲染与交互 =====
    renderTrend() {
      const el = this.$refs.trendRef
      if (!el) return
      const chart = echarts.init(el)
      const periods = this.trend.map(i => i.period)
      const total = this.trend.map(i => i.total)
      const completed = this.trend.map(i => i.completed)
      const exceptions = this.trend.map(i => i.exceptions)
      const onTime = this.trend.map(i => i.onTimeRate)
      chart.setOption({
        tooltip: { trigger: 'axis' },
        legend: { data: ['总数', '完成', '异常', '准时率'] },
        grid: { left: 30, right: 30, top: 30, bottom: 30 },
        xAxis: { type: 'category', data: periods },
        yAxis: [ { type: 'value', name: '数量' }, { type: 'value', name: '准时率(%)', max: 100 } ],
        series: [
          { name: '总数', type: 'bar', data: total },
          { name: '完成', type: 'bar', data: completed },
          { name: '异常', type: 'bar', data: exceptions },
          { name: '准时率', type: 'line', yAxisIndex: 1, data: onTime }
        ]
      })
      chart.off('click')
      chart.on('click', (params) => {
        const period = params.name
        this.setRangeByPeriod(period)
        this.loadAll()
      })
      this._trendChart = chart
    },
    renderDist() {
      const el = this.$refs.distRef
      if (!el) return
      const chart = echarts.init(el)
      const items = this.distribution
      chart.setOption({
        tooltip: { trigger: 'item' },
        legend: { orient: 'vertical', left: 'left' },
        series: [
          {
            type: 'pie', radius: '65%', center: ['50%', '50%'],
            data: items.map(i => ({ name: i.category, value: i.count }))
          }
        ]
      })
      chart.off('click')
      chart.on('click', (params) => {
        // 按业务状态本地过滤实时表格
        this.tableFilters.status = params.name
      })
      this._distChart = chart
    },
    renderException() {
      const el = this.$refs.exceptionRef
      if (!el) return
      const chart = echarts.init(el)
      const names = this.exceptions.map(i => i.exceptionName || i.exceptionType)
      const counts = this.exceptions.map(i => i.count)
      chart.setOption({
        tooltip: { trigger: 'axis' },
        xAxis: { type: 'category', data: names },
        yAxis: { type: 'value' },
        series: [ { type: 'bar', data: counts } ]
      })
      chart.off('click')
      chart.on('click', () => {
        // 跳转到发货单列表并预置异常状态（99）
        this.$router.push({ path: '/kanban/deliveryOrder', query: { status: 99 } })
      })
      this._exceptionChart = chart
    },
    // ===== 期段设定（与趋势 period 对应） =====
    setRangeByPeriod(period) {
      if (!period) return
      // day: YYYY-MM-DD, month: YYYY-MM, week: YYYY-ww
      if (/^\d{4}-\d{2}-\d{2}$/.test(period)) {
        const start = new Date(period + ' 00:00:00')
        const end = new Date(period + ' 23:59:59')
        this.filters.range = [this.formatDateTime(start), this.formatDateTime(end)]
        return
      }
      if (/^\d{4}-\d{2}$/.test(period)) {
        const [y, m] = period.split('-').map(n => parseInt(n, 10))
        const start = new Date(y, m - 1, 1, 0, 0, 0)
        const end = new Date(y, m, 0, 23, 59, 59) // 月末
        this.filters.range = [this.formatDateTime(start), this.formatDateTime(end)]
        return
      }
      if (/^\d{4}-\d{2}$/.test(period)) {
        // 同样匹配到上面的 month；若需要区分周，可在后端 period 加前缀
        return
      }
      // 兼容类似 2025-02（周次）字符串：视为该周的周一到周日
      const m = period.match(/^(\d{4})-(\d{1,2})$/)
      if (m) {
        const year = parseInt(m[1], 10)
        const week = parseInt(m[2], 10)
        const range = this.getISOWeekRange(year, week)
        this.filters.range = [this.formatDateTime(range[0]), this.formatDateTime(range[1])]
      }
    },
    getISOWeekRange(year, week) {
      // 近似计算：以周一为一周起始
      const simple = new Date(year, 0, 1 + (week - 1) * 7)
      const dow = simple.getDay() || 7 // 周日=7
      const monday = new Date(simple)
      monday.setDate(simple.getDate() - (dow - 1))
      const sunday = new Date(monday)
      sunday.setDate(monday.getDate() + 6)
      monday.setHours(0,0,0,0)
      sunday.setHours(23,59,59,999)
      return [monday, sunday]
    },
    formatDateTime(d) {
      const y = d.getFullYear()
      const m = String(d.getMonth() + 1).padStart(2, '0')
      const day = String(d.getDate()).padStart(2, '0')
      const hh = String(d.getHours()).padStart(2, '0')
      const mm = String(d.getMinutes()).padStart(2, '0')
      const ss = String(d.getSeconds()).padStart(2, '0')
      return `${y}-${m}-${day} ${hh}:${mm}:${ss}`
    },
    // ===== 导出功能 =====
    exportRealtime() {
      const headers = ['看板编码','业务状态','收货库房','发货库房','要求到货','计划发货','创建时间']
      const rows = this.realtimeFiltered.map(r => [
        r.kanbanCode || '', r.businessStatus || '', r.receiverWarehouse || '', r.senderWarehouse || '',
        this.formatDateCell(r.requiredDeliveryTime), this.formatDateCell(r.plannedDeliveryTime), this.formatDateCell(r.createTime)
      ])
      const csv = this.toCSV(headers, rows)
      const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
      saveAs(blob, `dashboard_realtime_${Date.now()}.csv`)
    },
    exportExceptions() {
      const headers = ['异常类型','数量']
      const rows = this.exceptions.map(e => [e.exceptionName || e.exceptionType || '', e.count || 0])
      const csv = this.toCSV(headers, rows)
      const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
      saveAs(blob, `dashboard_exceptions_${Date.now()}.csv`)
    },
    exportCharts() {
      const charts = [this._trendChart, this._distChart, this._exceptionChart]
      const names = ['trend','distribution','exceptions']
      charts.forEach((c, idx) => {
        if (!c) return
        const dataURL = c.getDataURL({ type: 'png', pixelRatio: 2, backgroundColor: '#fff' })
        const blob = this.dataURLtoBlob(dataURL)
        saveAs(blob, `dashboard_${names[idx]}_${Date.now()}.png`)
      })
    },
    toCSV(headers, rows) {
      const escape = v => {
        const s = String(v == null ? '' : v)
        if (s.includes(',') || s.includes('\n') || s.includes('"')) {
          return '"' + s.replace(/"/g, '""') + '"'
        }
        return s
      }
      const head = headers.map(escape).join(',')
      const body = rows.map(r => r.map(escape).join(',')).join('\n')
      return head + '\n' + body
    },
    dataURLtoBlob(dataURL) {
      const parts = dataURL.split(';base64,')
      const contentType = parts[0].split(':')[1]
      const raw = atob(parts[1])
      const uInt8Array = new Uint8Array(raw.length)
      for (let i = 0; i < raw.length; i++) {
        uInt8Array[i] = raw.charCodeAt(i)
      }
      return new Blob([uInt8Array], { type: contentType })
    },
    formatDateCell(val) {
      if (!val) return ''
      const d = typeof val === 'string' ? new Date(val) : val
      return this.formatDateTime(d)
    },
    // ===== 行交互 =====
    handleRowDblClick(row) {
      // 跳转到发货单列表并带上看板编码
      this.$router.push({ path: '/kanban/deliveryOrder', query: { kanbanCode: row.kanbanCode } })
      // 同时复制编码到剪贴板，便于搜索
      if (navigator.clipboard && row.kanbanCode) {
        navigator.clipboard.writeText(row.kanbanCode)
        this.$message.success('看板编码已复制')
      }
    }
  }
}
</script>

<style scoped>
.filter-bar { margin-bottom: 8px; }
.summary-row { margin-bottom: 12px; }
.metric { color: #666; font-size: 13px; }
.value { font-size: 22px; font-weight: 600; }
.value.success { color: #67C23A; }
.value.warning { color: #E6A23C; }
.value.info { color: #909399; }
.chart-card { height: 420px; }
.chart { width: 100%; height: 380px; }
.mb8 { margin-bottom: 8px; }
.sub-filter { margin-bottom: 8px; display: flex; align-items: center; }
</style>